-- Jednostka centralna

library IEEE;
use IEEE.Std_Logic_1164.all;
use IEEE.Std_Logic_Arith.all;
use work.constants.all;

entity CU2 is
  generic (delay : time := 5 ns);
  port (CLOCK, RESET            : in std_logic;
        INSTR, ADRARG1, ADRARG2 : in std_logic_vector(1 downto 0);
        ARG1, ARG2              : in std_logic_vector(3 downto 0);
        CU_GA                   : out std_logic_vector(2 downto 0);
        CU_ALU_INSTR,CU_ERROR           : out std_logic_vector(1 downto 0);
        CU_ROM_LAE, CU_ROM_R, CU_ROM_IE, CU_ROM_OE : out std_logic;
        CU_PC_INCR, CU_PC_RESET, CU_RI_LAE, CU_DE_DECODE, CU_RN_LAE : out std_logic;
        CU_RTMP_IE,CU_RTMP_OE,CU_REGX_IE, CU_REGY_IE, CU_ALU_START, CU_ALU_OE : out std_logic;
        CU_R1_IE, CU_R1_OE, CU_R2_IE, CU_R2_OE,CU_R3_IE, CU_R3_OE,CU_R4_IE, CU_R4_OE,CU_R5_IE, CU_R5_OE, CU_R6_IE, CU_R6_OE : out std_logic);
       
    end entity CU2;

architecture CU_arch of CU2 is
begin
  process(CLOCK, RESET)
    variable state : integer := 0;
begin
    if(RESET = '0') then
      state := 0;
      CU_PC_RESET <= '0';
      CU_ERROR <= NO_ERROR;
      
    elsif(rising_edge(CLOCK)) then
      case state is
        when 0 =>
                 CU_PC_RESET <= '1';
                 CU_ALU_START <= '1';
                 CU_DE_DECODE <= '1';
                 CU_GA <= GA_PC;
                 CU_ROM_LAE <= '0';
                 CU_R1_IE<='1';
                 CU_R1_OE<='1';
                 CU_R2_IE<='1';
                 CU_R2_OE<='1';
                 CU_R3_IE<='1';
                 CU_R3_OE<='1';
                 CU_R4_IE<='1';
                 CU_R4_OE<='1';
                 CU_R5_IE<='1';
                 CU_R5_OE<='1';
                 CU_R6_IE<='1';
                 CU_R6_OE<='1';
                 CU_RTMP_IE<='1';
                 CU_RTMP_OE<='1';
                 CU_REGX_IE<='1';
                 CU_REGY_IE<='1';
                 
                 state := 1;
                 
        
        when 1 =>
                 CU_ROM_LAE <= '1';
                 CU_PC_INCR <= '0';
                 CU_ROM_R <= '0';
                 CU_ROM_IE <= '0';
                 state := 2;
                 
        when 2 =>
                 CU_PC_INCR <= '1';
                 CU_ROM_R <= '1';
                 CU_ROM_IE <= '1';
                 CU_ROM_OE <= '0';
                 CU_RI_LAE <= '0';
                 CU_RN_LAE <= '0';
                 state := 3;
                 
        when 3 =>
                CU_ROM_OE <= '1';
                CU_RI_LAE <= '1';
                CU_RN_LAE <= '1';
                CU_DE_DECODE <= '0';
                state := 4;
        
        when 4 =>
          
          case INSTR is
                when XCHG => state:=5;
                when NEG => state:=20;
                when others =>
                CU_ERROR <= ERR_BAD_INSTR;
                state := 13;
          end case;
          
        when 5 =>          
          case ARG1 is
              when "0001" => CU_R1_OE <='0';
                             CU_RTMP_IE <='0';
                             state:=6;
              when "0010" => CU_R2_OE <='0';
                             CU_RTMP_IE<='0';
                             state:=6;
              when "0011" => CU_R3_OE <='0';
                             CU_RTMP_IE <='0';
                             state:=6;
              when "0100" => CU_R4_OE <='0';
                             CU_RTMP_IE<='0';
                             state:=6;
              when "0101" => CU_R5_OE <='0';
                             CU_RTMP_IE <='0';
                             state:=6;
              when "0110" => CU_R6_OE <='0';
                             CU_RTMP_IE<='0';
                             state:=6;
              when others=>  
                CU_ERROR <= ERR_BAD_INSTR;
                state := 13;            
      end case;
      
      
      when 6 =>          
          case ARG1 is
              when "0001" => CU_R1_OE <='1';
                             CU_RTMP_IE <='1';
                             CU_GA <= GA_PC;
                             CU_ROM_LAE <= '0';
                             state:=7;
                             
              when "0010" => CU_R2_OE <='1';
                             CU_RTMP_IE<='1';
                             CU_GA <= GA_PC;
                             CU_ROM_LAE <= '0';
                             state:=7;
                             
              when "0011" => CU_R3_OE <='1';
                             CU_RTMP_IE <='1';
                             CU_GA <= GA_PC;
                             CU_ROM_LAE <= '0';
                             state:=7;
                             
              when "0100" => CU_R4_OE <='1';
                             CU_RTMP_IE<='1'; 
                             CU_GA <= GA_PC;
                             CU_ROM_LAE <= '0';
                             state:=7;
                             
              when "0101" => CU_R5_OE <='1';
                             CU_RTMP_IE <='1';
                             CU_GA <= GA_PC;
                             CU_ROM_LAE <= '0';
                             state:=7;
                             
              when "0110" => CU_R6_OE <='1';
                             CU_RTMP_IE<='1';
                             CU_GA <= GA_PC;
                             CU_ROM_LAE <= '0';
                             state:=7;
                             
              when others=>  
                CU_ERROR <= ERR_BAD_INSTR;
                state := 13;            
      end case;
            
            
      when 7 =>   
                 CU_ROM_LAE <= '1';
                 CU_PC_INCR <= '0';
                 CU_ROM_R <= '0';
                 CU_ROM_IE <= '0';
                 state := 8;

      when 8=>
                 CU_PC_INCR <= '1';
                 CU_ROM_R <= '1';
                 CU_ROM_IE <= '1';
                 CU_ROM_OE <= '0';
                 CU_RI_LAE <= '0';
                 CU_RN_LAE <= '0';
                 CU_DE_DECODE <= '1';
                 state := 9;
      when 9 =>
                CU_ROM_OE <= '1';
                CU_RI_LAE <= '1';
                CU_RN_LAE <= '1';
                CU_DE_DECODE <= '0';
                state := 10;
                
      when 10 =>
                
           case ARG2 is
                when "0001" => CU_R1_OE <='0';
                               state:=11;
                when "0010" => CU_R2_OE <='0';
                               state:=11;
                when "0011" => CU_R3_OE <='0';
                               state:=11;
                when "0100" => CU_R4_OE <='0';
                               state:=11;
                when "0101" => CU_R5_OE <='0';
                               state:=11;
                when "0110" => CU_R6_OE <='0';
                               state:=11;
                when others=>  
                               CU_ERROR <= ERR_BAD_INSTR;
                                state := 13;            
          end case;
                
        
        
      when 11 =>
              
           case ARG1 is
                when "0001" => CU_R1_IE <='0';
                               state:=12;
                when "0010" => CU_R2_IE <='0';
                               state:=12;
                when "0011" => CU_R3_IE <='0';
                               state:=12;
                when "0100" => CU_R4_IE <='0';
                               state:=12;
                when "0101" => CU_R5_IE <='0';
                               state:=12;
                when "0110" => CU_R6_IE <='0';
                               state:=12;
                when others=>  
                               CU_ERROR <= ERR_BAD_INSTR;
                                state := 13;            
          end case;
        
      when 12 =>
           
           case ARG1 is
                when "0001" => CU_R1_IE <='1';
                               state:=14;
                when "0010" => CU_R2_IE <='1';
                               state:=14;
                when "0011" => CU_R3_IE <='1';
                               state:=14;
                when "0100" => CU_R4_IE <='1';
                               state:=14;
                when "0101" => CU_R5_IE <='1';
                               state:=14;
                when "0110" => CU_R6_IE <='1';
                               state:=14;
                when others=>  
                               CU_ERROR <= ERR_BAD_INSTR;
                                state := 13;            
          end case;

          
    when 14 =>
      case ARG2 is
                when "0001" => CU_R1_OE <='1';
                               CU_R1_IE <='0';
                               CU_RTMP_OE<='0';
                               state:=18;
                when "0010" => CU_R2_OE <='1';
                               CU_R2_IE <='0';
                               CU_RTMP_OE<='0';
                               state:=18;
                when "0011" => CU_R3_OE <='1';
                               CU_R3_IE <='0';
                               CU_RTMP_OE<='0';
                               state:=18;
                when "0100" => CU_R4_OE<='1';
                               CU_R4_IE <='0';
                               CU_RTMP_OE<='0';
                               state:=18;
                when "0101" => CU_R5_OE <='1';
                               CU_R5_IE <='0';
                               CU_RTMP_OE<='0';
                               state:=18;
                               
                when "0110" => CU_R6_OE <='1';
                               CU_R6_IE <='0';
                               CU_RTMP_OE<='0';
                               state:=18;
                               
                when others=>  
                               CU_ERROR <= ERR_BAD_INSTR;
                                state := 13;            
          end case;
          
  when 18 => case ARG2 is
                when "0001" => CU_R1_IE <='1';
                               state:=0;
                when "0010" => CU_R2_IE <='1';
                               state:=0;
                when "0011" => CU_R3_IE <='1';
                               state:=0;
                when "0100" => CU_R4_IE <='1';
                               state:=0;
                when "0101" => CU_R5_IE <='1';
                               state:=0;
                when "0110" => CU_R6_IE <='1';
                               state:=0;
                when others=>  
                               CU_ERROR <= ERR_BAD_INSTR;
                                state := 13;            
          end case;

                

            
        
    when 20 =>
      case ARG1 is
              when "0001" => CU_R1_OE <='0';
                             CU_REGX_IE <='0';
                             state:=15;
              when "0010" => CU_R2_OE <='0';
                             CU_REGX_IE<='0';
                             state:=15;
              when "0011" => CU_R3_OE <='0';
                             CU_REGX_IE <='0';
                             state:=15;
              when "0100" => CU_R4_OE <='0';
                             CU_REGX_IE<='0';
                             state:=15;
              when "0101" => CU_R5_OE <='0';
                             CU_REGX_IE <='0';
                             state:=15;
              when "0110" => CU_R6_OE <='0';
                             CU_REGX_IE<='0';
                             state:=15;
              when others=>  
                CU_ERROR <= ERR_BAD_INSTR;
                state := 13;            
      end case;
        
        
        
        
      
    when 15 =>
      case ARG1 is
              when "0001" => CU_R1_OE <='1';
                             CU_REGX_IE <='1';
                             CU_ALU_INSTR <= NEG;
                             CU_ALU_START <= '0';
                             state:=16;
              when "0010" => CU_R2_OE <='1';
                             CU_REGX_IE<='1';
                             CU_ALU_INSTR <= NEG;
                             CU_ALU_START <= '0';
                             state:=16;
              when "0011" => CU_R3_OE <='1';
                             CU_REGX_IE <='1';
                             CU_ALU_INSTR <= NEG;
                             CU_ALU_START <= '0';
                             state:=16;
              when "0100" => CU_R4_OE <='1';
                             CU_REGX_IE<='1';
                             CU_ALU_INSTR <= NEG;
                             CU_ALU_START <= '0';
                             state:=16;
              when "0101" => CU_R5_OE <='1';
                             CU_REGX_IE <='1';
                             CU_ALU_INSTR <= NEG;
                             CU_ALU_START <= '0';
                             state:=16;
              when "0110" => CU_R6_OE <='1';
                             CU_REGX_IE<='1';
                             CU_ALU_INSTR <= NEG;
                             CU_ALU_START <= '0';
                             state:=16;
              when others=>  
                CU_ERROR <= ERR_BAD_INSTR;
                state := 13;            
      end case;
      
      
    when 16 =>
        case ARG1 is
              when "0001" => CU_R1_IE <='0';
                             CU_ALU_OE<='0';
                             state:=17;
              when "0010" => CU_R2_IE <='0';
                             CU_ALU_OE<='0';
                             state:=17;
              when "0011" => CU_R3_IE <='0';
                             CU_ALU_OE<='0';
                             state:=17;
              when "0100" => CU_R4_IE <='0';
                             CU_ALU_OE<='0';
                             state:=17;
              when "0101" => CU_R5_IE <='0';
                             CU_ALU_OE<='0';
                             state:=17;
              when "0110" => CU_R6_IE <='0';
                             CU_ALU_OE<='0';
                             state:=17;
              when others=>  
                CU_ERROR <= ERR_BAD_INSTR;
                state := 13;            
      end case;
       
        when 17 =>
          case ARG1 is
              when "0001" => CU_R1_IE <='1';
                             CU_ALU_OE<='1';
                             state:=0;
              when "0010" => CU_R2_IE <='1';
                             CU_ALU_OE<='1';
                             state:=0;
              when "0011" => CU_R3_IE <='1';
                             CU_ALU_OE<='1';
                             state:=0;
              when "0100" => CU_R4_IE <='1';
                             CU_ALU_OE<='1';
                             state:=0;
              when "0101" => CU_R5_IE <='1';
                             CU_ALU_OE<='1';
                             state:=0;
              when "0110" => CU_R6_IE <='1';
                             CU_ALU_OE<='1';
                             state:=0;
              when others=>  
                CU_ERROR <= ERR_BAD_INSTR;
                state := 13;            
      end case;
                             
                        
        when 13 =>
    
        when others =>
          CU_ERROR <= ERR_BAD_INSTR;
   
    end case;
   end if;
  end process;
end architecture CU_arch;
